package maosui.websocket;


import maosui.model.RoomEntity;
import maosui.model.UserEntity;
import net.sf.json.JSONObject;

import javax.websocket.Session;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class LiveWebSocket {

    protected static final Hashtable<Integer,Hashtable<Integer, LiveWebSocket>> connections = new Hashtable<Integer, Hashtable<Integer, LiveWebSocket>>();

    protected final String nickname = "";
    protected Session session;
    protected int uid;
    protected int cid;
    protected int rid;
    protected RoomEntity room;
    protected UserEntity user;

    public void start(Session session) {
        this.session = session;
        RequestParams request = new RequestParams(session.getQueryString());
        uid = request.getInt("uid");
        cid = request.getInt("cid");
        rid = request.getInt("rid");
        if(uid > 0 && (cid > 0 || rid > 0)){
            if(cid > 0){
                room = DBManager.getRoomByCid(cid);
                if(room == null){
                    sendMessage("请检查岗位ID是否正确");
                    return;
                }
                rid = room.getId();
            }else if(rid > 0){
                room = DBManager.getRoomByCid(rid);
                if(room == null){
                    sendMessage("请检查岗位ID是否正确");
                    return;
                }
                cid = room.getCid();
            }
            user = DBManager.getUserById(uid);
            if(user == null){
                sendMessage("请检查UID是否正确");
                return;
            }

            if(getClientByUid(uid) != null){
                sendEventMessage("error", "你已在其他浏览器窗口中打开过视频");
                close();
                return;
            }

            sendMessage("Welcome " + user.getUsername() + " to live");

            if(user.getUserType() == UserType.COMPANY){
                sendEventMessageToAll("company_online", room.getId());
            }else if(user.getUserType() == UserType.SEEKER){
                sendEventMessageToUser(room.getUid(), "seeker_online", user);
            }else{
                sendMessage("错误的用户类型");
                return;
            }


            System.out.println("on:" + connections.keySet() + "," +cid);
            System.out.println("onlines: "+connections.get(cid));


            //connections.put(uid, this);
            addClient(uid, this);
            //connections.pu
            HashMap<String,Object> info = new HashMap<String, Object>();
            info.put("user", JSONObject.fromObject(user));
            info.put("room", JSONObject.fromObject(room));
            info.put("uid", uid);
            info.put("cid", cid);
            info.put("rid", rid);

            if(user.getUserType() == UserType.SEEKER){
                info.put("queueIndex", getOnlineSeekerIds().size());
            }

            sendEventMessage("init", info);

            //String message = String.format("* %s %s", nickname, "has joined.");
            //broadcast(message);
        }else{
            sendMessage("请检查 QueryString 参数是否正确!");
        }
    }

    public void end() {

        removeClient(uid);

        /*String message = String.format("* %s %s",
                nickname, "has disconnected.");
        broadcast(message);*/
    }

    public void incoming(String message) {
        if (Utils.isJSONString(message) && Utils.isJSONObject(message)){
            JSONObject json = JSONObject.fromObject(message);
            String method = json.getString("event_type");
            if (method != null) {
                try {
                    Class<?> cls = this.getClass();
                    Method m = cls.getMethod(method, cls, JSONObject.class);
                    Object o = m.invoke(this, this, json.getJSONObject("event_data"));
                    if(o != null){
                        sendMessage(o.toString());
                    }
                } catch (NoSuchMethodException e) {
                    System.err.println("NoSuchMethodException: " + e.getMessage());
                } catch (InvocationTargetException e) {
                    System.err.println("InvocationTargetException: " + e.getMessage());
                } catch (IllegalAccessException e) {
                    System.err.println("IllegalAccessException: " + e.getMessage());
                }
                System.out.println("call this method " + method);
            }
        }
    }

    /**
     * 发送文本信息给指定用户
     * @param uid int 用户ID
     * @param msg String 信息内容
     */
    public void sendMessageToUid(int uid, String msg){
        //LiveWebSocket client = connections.get(uid);
        LiveWebSocket client = getClientByUid(uid);
        if(client != null){
            client.sendMessage(msg);
        }
    }

    /**
     * 发送文本信息给所有用户
     * @param msg String 信息内容
     */
    public void sendMessageToAll(String msg){
        //Collection<LiveWebSocket> lives = connections.values();
        Hashtable<Integer, LiveWebSocket> list = getConnections();
        if(list == null)return;
        Collection<LiveWebSocket> lives = list.values();
        for(LiveWebSocket live: lives){
            if(live == this)continue;
            sendMessage(msg, live);
        }

    }

    /**
     * 发送信息给当前用户
     * @param message String 信息内容
     */
    public void sendMessage(String message){
        sendMessage(message, this);
    }

    /**
     * 发送信息给指定用户
     * @param msg String 信息内容
     * @param client Live 用户 Live
     */
    public void sendMessage(String msg, LiveWebSocket client){
        try {
            synchronized (client) {
                client.session.getBasicRemote().sendText(msg);
            }
        } catch (IOException e) {
            System.err.println("Chat Error: Failed to send message to client");
            connections.remove(client.getUid());
            try {
                client.session.close();
            } catch (IOException e1) {
                // Ignore
            }
        }
    }

    /**
     * 发送事件信息给当前用户
     * @param eventType String 事件类型
     * @param message Object 信息内容
     */
    public void sendEventMessage(String eventType, Object message){
        sendMessage(Utils.ConvertToEventMessage(eventType, message));
    }


    /**
     * 发送事件给指定用户
     * @param user_id int 用户ID
     * @param eventType String 事件类型
     * @param message Object 信息内容
     */
    public void sendEventMessageToUser(int user_id, String eventType, Object message){
        sendMessageToUid(user_id, Utils.ConvertToEventMessage(eventType, message));
    }

    /**
     * 发送事件给所有用户
     * @param eventType String 事件类型
     * @param message Object 信息内容
     */
    public void sendEventMessageToAll(String eventType, Object message){
        sendMessageToAll(Utils.ConvertToEventMessage(eventType, message));
    }


    private void broadcast(String msg) {
        Hashtable<Integer, LiveWebSocket> list = getConnections();
        if(list == null)return;
        for (LiveWebSocket client : list.values()) {
            try {
                synchronized (client) {
                    client.session.getBasicRemote().sendText(msg);
                }
            } catch (IOException e) {
                System.err.println("Chat Error: Failed to send message to client");
                connections.remove(client.getUid());
                try {
                    client.session.close();
                } catch (IOException e1) {
                    // Ignore
                }
                String message = String.format("* %s %s",
                        client.nickname, "has been disconnected.");
                broadcast(message);
            }
        }
    }

    public Hashtable<Integer, LiveWebSocket> getConnections(){
        return connections.get(cid);
    }

    public void addClient(int uid, LiveWebSocket live){
        Hashtable<Integer, LiveWebSocket> s = connections.get(cid);
        if(s == null){
            s = new Hashtable<Integer, LiveWebSocket>();
            s.put(uid, live);
            connections.put(cid,s);
        }else{
            s.put(uid, live);
        }
    }

    public void removeClient(int uid){
        Hashtable<Integer, LiveWebSocket> s = connections.get(cid);
        if(s != null){
            if(uid == this.uid){
                if(this == s.get(uid)){
                    s.remove(uid);
                    _offline();
                }
            }else {
                s.remove(uid);
                _offline();
            }
        }
    }

    protected void _offline(){
        if(user != null){
            if(user.getUserType() == UserType.COMPANY){
                sendEventMessageToAll("company_offline", room.getId());
            }else if(user.getUserType() == UserType.SEEKER){
                sendEventMessageToUser(room.getUid(), "seeker_offline", uid);
            }
        }
    }

    /**
     * 关闭当前Session
     */
    public void close(){
        if(session != null && session.isOpen()){
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * getClientByUid
     * @param uid int 用户ID
     * @return LiveWebSocket
     */
    public LiveWebSocket getClientByUid(int uid){
        Hashtable<Integer, LiveWebSocket> s = connections.get(cid);
        if(s != null){
            return s.get(uid);
        }
        return null;
    }

    /**
     * 获取在线用户ID列表
     * @return Set<Integer>
     */
    public Set<Integer> getOnlineUserIds(){
        Hashtable<Integer, LiveWebSocket> s = connections.get(cid);
        if(s != null){
            return s.keySet();
        }
        return null;
    }

    /**
     * 获得在线的求职者用户
     * @return List<Integer>
     */
    public List<Integer> getOnlineSeekerIds(){
        Hashtable<Integer, LiveWebSocket> s = connections.get(cid);
        List<Integer> list = new ArrayList<Integer>();
        if(s != null){
            Enumeration<LiveWebSocket> en = s.elements();
            while (en.hasMoreElements()){
                LiveWebSocket liveWebSocket = en.nextElement();
                if (liveWebSocket.getUser().getUserType() == UserType.COMPANY){
                    continue;
                }
                list.add(liveWebSocket.getUid());
            }
        }
        return list;
    }

    /**
     * 获取在线用户对象列表
     * @return List<LiveWebSocket>
     */
    public List<LiveWebSocket> getOnlineSeekers(){
        Hashtable<Integer, LiveWebSocket> s = getConnections();
        List<LiveWebSocket> liveWebSockets = new ArrayList<LiveWebSocket>();
        if(s != null){
            Enumeration<LiveWebSocket> en = s.elements();
            while (en.hasMoreElements()){
                LiveWebSocket liveWebSocket = en.nextElement();
                if (liveWebSocket.getUser().getUserType() == UserType.COMPANY){
                    continue;
                }
                liveWebSockets.add(liveWebSocket);
            }
        }
        return liveWebSockets;
    }

    /**
     * 获得当前Session
     * @return Session
     */
    public Session getSession() {
        return session;
    }

    /**
     * 获得当前UID
     * @return int
     */
    public int getUid() {
        return uid;
    }

    public int getRid() {
        return rid;
    }

    public RoomEntity getRoom() {
        return room;
    }

    public UserEntity getUser() {
        return user;
    }

    /**
     * 用户类型
     */
    static class UserType{
        /**
         * 求职者用户
         */
        public final static int SEEKER = 1;
        /**
         * 企业用户
         */
        public final static int COMPANY = 2;
    }
}

